package aggregation.simulator.snapshot;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import common.peer.PeerAddress;

public class Snapshot {
	// TODO : set the real average ^^
	private static final double REAL_AVERAGE = 15;
	
	private static HashMap<PeerAddress, PeerInfo> peers = new HashMap<PeerAddress, PeerInfo>();
	private static int counter = 0;
	private static String FILENAME = "aggregation.out";

//-------------------------------------------------------------------
	public static void init(int numOfStripes) {
		FileIO.write("", FILENAME);
	}

//-------------------------------------------------------------------
	public static void addPeer(PeerAddress address) {
		peers.put(address, new PeerInfo());
	}

//-------------------------------------------------------------------
	public static void removePeer(PeerAddress address) {
		peers.remove(address);
	}

//-------------------------------------------------------------------
	public static void updateNum(PeerAddress address, double num) {
		PeerInfo peerInfo = peers.get(address);
		
		if (peerInfo == null)
			return;
		
		peerInfo.updateNum(num);
	}
	
//-------------------------------------------------------------------
	public static void updateCyclonPartners(PeerAddress address, ArrayList<PeerAddress> partners) {
		PeerInfo peerInfo = peers.get(address);
		
		if (peerInfo == null)
			return;
		
		peerInfo.updateCyclonPartners(partners);
	}

//-------------------------------------------------------------------
	public static void report() {
		String str = new String();
		str += "current time: " + counter++ + "\n";
		if(counter > 201){
			System.exit(0);
		}
		str += reportNetworkState();
		str += verifyNetworkSize(); // Modified to provide info for task 2
		//str += reportDetailes();
		str += "###\n";
		
/////////// Print relevant infos for Task 1
		
		// Print average of estimations
		str += estimationAverage();
		
		// Print standard deviation of these estimations
		str += estimationSigma();
		
		str += "###\n";
///////////////////////////////////////////
		
		System.out.println(str);
		FileIO.append(str, FILENAME);
	}

private static String estimationAverage() {
	double sum = 0;
	for(Map.Entry<PeerAddress, PeerInfo> entry : peers.entrySet()){
		sum += entry.getValue().getNum();
	}
	String str = new String("Average of estimations : ");
	str += sum/peers.size();
	str += "\n";
	
	return str;
}

private static String estimationSigma() {
	double sum1 = 0, sum2 = 0;
	for(Map.Entry<PeerAddress, PeerInfo> entry : peers.entrySet()){
		sum1 += Math.pow(entry.getValue().getNum(), 2);
		sum2 += entry.getValue().getNum();
	}
	
	String str = new String("Standard deviation of estimations : ");
	str += Math.sqrt(sum1/peers.size() - Math.pow(sum2/peers.size(), 2));
	str += "\n";
	return str;
}

//-------------------------------------------------------------------
	private static String reportNetworkState() {
		String str = new String("---\n");
		int totalNumOfPeers = peers.size();
		str += "total number of peers: " + totalNumOfPeers + "\n";

		return str;		
	}
	
//-------------------------------------------------------------------
	private static String reportDetailes() {
		PeerInfo peerInfo;
		String str = new String("---\n");

		for (PeerAddress peer : peers.keySet()) {
			peerInfo = peers.get(peer);
		
			str += "peer: " + peer;
			str += ", cyclon parters: " + peerInfo.getCyclonPartners();
			str += "\n";
		}
		
		return str;
	}

//-------------------------------------------------------------------
	private static String verifyNetworkSize() {
		PeerInfo peerInfo;
		int correct = 0;
		double estimated = 0;
		String str = new String("---\n");

		for (PeerAddress peer : peers.keySet()) {
			peerInfo = peers.get(peer);
//			estimated = 1 / peerInfo.getNum();
			estimated = peerInfo.getNum();
			str += peer + " --> estimated average: " + estimated + "\n";
			if (Math.abs(estimated - REAL_AVERAGE) <= 1) // Estimated correct at +/- 1
				correct++;
		}
		
		str += "estimated correctly: " + correct + " %\n";
		return str;
	}

}
